In [1]:
import pandas as pd
import altair as alt
In [2]:
ruta = r"C:\Users\maria\Downloads\Python -QLAB\Base de Eventos de Protesta del Perú_1980_2025.xlsx"
data = pd.read_excel(ruta)
data.columns = data.columns.str.lower()
data['número_heridos'] = pd.to_numeric(data['número_heridos'], errors='coerce').fillna(0)
data['número_muertos'] = pd.to_numeric(data['número_muertos'], errors='coerce').fillna(0)
data.head()
Out[2]:
| id | periódico | periódico_id | día | mes_id | mes | año | fecha | presidente_id | presidente | ... | institución_1 | institución_2 | institución_3 | institución_id | reclamo_t | reclamo | reclamo_id | sub_reclamo | sub_reclamo_id | comentar_t | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | Expreso | 5.0 | 1 | 1 | Enero | 1980 | ############ | 1 | Morales Bermúdez | ... | Empresas periodísticas | Periodicos y diarios. | NaN | 909.0 | Exigen que las empresas periodísticas les otor... | Laborales | 1 | Bonificaciones | 105 | NaN |
| 1 | 2 | Expreso | 5.0 | 3 | 1 | Enero | 1980 | ############ | 1 | Morales Bermúdez | ... | Instituto Peruano de Seguridad Social | NaN | NaN | 712.0 | Demandan una mejora en condiciones salariales. | Laborales | 1 | Aumentos salariales | 101 | Exigen además: recategorización, aumento gener... |
| 2 | 3 | Expreso | 5.0 | 4 | 1 | Enero | 1980 | ############ | 1 | Morales Bermúdez | ... | Ministerio de Justicia | Centro de Readaptación Social de Chorrillos | NaN | 105.0 | Protestan por la mala alimentación recibida en... | Servicios | 4 | Alimentación | 407 | 15 internas resultaron heridas. |
| 3 | 4 | Expreso / El Comercio | 6.0 | 4 | 1 | Enero | 1980 | ############ | 1 | Morales Bermúdez | ... | Empresas periodísticas | Empresa Periodistica Nacional S.A. | NaN | 909.0 | Protestan contra medidas de la empresa que ate... | Laborales | 1 | Mejores condiciones laborales | 104 | Huelga declarada ilegal por el gobierno. Inici... |
| 4 | 5 | El Comercio | 7.0 | 4 | 1 | Enero | 1980 | ############ | 1 | Morales Bermúdez | ... | Municipalidades Provinciales de Cusco | Cusco | NaN | 508.0 | Denuncian el despido arbitrario de trabajadores. | Laborales | 1 | Estabilidad laboral | 109 | También demandan la destitución de cuatro func... |
5 rows × 51 columns
In [3]:
variables_interes = ['año', 'región', 'número_heridos', 'número_muertos', 'sector_1']
data_estudio = data[variables_interes].copy()
data_estudio['número_heridos'] = data_estudio['número_heridos'].fillna(0)
data_estudio['número_muertos'] = data_estudio['número_muertos'].fillna(0)
In [4]:
def categorizar_protesta(fila):
if fila == 0:
return "Pacífica/Sin víctimas"
elif fila <= 5:
return "Violencia Moderada"
else:
return "Violencia Alta"
data_estudio['total_victimas'] = data_estudio['número_heridos'] + data_estudio['número_muertos']
data_estudio['intensidad'] = data_estudio['total_victimas'].apply(categorizar_protesta)
print(data_estudio[['total_victimas', 'intensidad']].head())
total_victimas intensidad 0 0.0 Pacífica/Sin víctimas 1 0.0 Pacífica/Sin víctimas 2 15.0 Violencia Alta 3 0.0 Pacífica/Sin víctimas 4 0.0 Pacífica/Sin víctimas
In [5]:
grafico_1 = alt.Chart(data_estudio).mark_line(point=True).encode(
x = alt.X('año:O', title='Año'),
y = alt.Y('count():Q', title='Cantidad de Protestas'),
tooltip = ['año', 'count()']
).properties(title='Evolución de las Protestas en el Perú', width=500).interactive()
In [6]:
import altair as alt
alt.data_transformers.disable_max_rows()
Out[6]:
DataTransformerRegistry.enable('default')
In [7]:
grafico_1.display()
In [8]:
top_regiones = data_estudio['región'].value_counts().head(10).index.tolist()
data_top = data_estudio[data_estudio['región'].isin(top_regiones)]
grafico_2 = alt.Chart(data_top).mark_bar().encode(
x = alt.X('count():Q', title='Número de Eventos'),
y = alt.Y('región:N', sort='-x', title='Departamento'),
color = alt.Color('intensidad:N', title='Nivel de Intensidad'),
tooltip = ['región', 'intensidad', 'count()']
).properties(title='Intensidad de Protestas en Regiones Top', width=500)
In [9]:
grafico_2.display()
In [10]:
variables_interes1 = ['año', 'región', 'periódico', 'número_muertos', 'sector_1']
data_estudio1 = data[variables_interes1].copy()
tabla = pd.crosstab(data_estudio1['periódico'], data_estudio1['sector_1'], normalize='index') * 100
In [11]:
data_periodicos = data_estudio1.assign(periódico=data_estudio1['periódico'].str.split('/'))
data_periodicos = data_periodicos.explode('periódico')
data_periodicos['periódico'] = data_periodicos['periódico'].str.strip()
In [12]:
tabla = pd.crosstab(data_periodicos['sector_1'], data_periodicos['periódico'], normalize='columns') * 100
tabla_altair = tabla.reset_index()
tabla_melted = tabla_altair.melt(id_vars='sector_1', var_name='periódico', value_name='porcentaje')
In [14]:
grafico_final = alt.Chart(tabla_melted).mark_bar().encode(
x = alt.X('porcentaje:Q', title='Porcentaje de Cobertura (%)'),
y = alt.Y('sector_1:N', sort='-x', title='Sector de la Protesta'),
color = alt.Color('periódico:N', title='Diario'),
tooltip = ['periódico', 'sector_1', 'porcentaje']
).properties(
title='Agenda Mediática: Distribución de Sectores por Diario (Valores Separados)',
width=600,
height=400
).interactive()
grafico_final.display()